package com.baomidou.kisso.common.bcprov.asn1.x509;

import java.io.IOException;
import java.util.Enumeration;

import com.baomidou.kisso.common.bcprov.asn1.ASN1Encodable;
import com.baomidou.kisso.common.bcprov.asn1.ASN1EncodableVector;
import com.baomidou.kisso.common.bcprov.asn1.ASN1InputStream;
import com.baomidou.kisso.common.bcprov.asn1.ASN1Object;
import com.baomidou.kisso.common.bcprov.asn1.ASN1Primitive;
import com.baomidou.kisso.common.bcprov.asn1.ASN1Sequence;
import com.baomidou.kisso.common.bcprov.asn1.ASN1TaggedObject;
import com.baomidou.kisso.common.bcprov.asn1.DERBitString;
import com.baomidou.kisso.common.bcprov.asn1.DERSequence;

/**
 * The object that contains the public key stored in a certficate.
 * <p>
 * The getEncoded() method in the public keys in the JCE produces a DER
 * encoded one of these.
 */
public class SubjectPublicKeyInfo extends ASN1Object {

	private AlgorithmIdentifier algId;

	private DERBitString keyData;


	public static SubjectPublicKeyInfo getInstance( ASN1TaggedObject obj, boolean explicit ) {
		return getInstance(ASN1Sequence.getInstance(obj, explicit));
	}


	public static SubjectPublicKeyInfo getInstance( Object obj ) {
		if ( obj instanceof SubjectPublicKeyInfo ) {
			return (SubjectPublicKeyInfo) obj;
		} else if ( obj != null ) {
			return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj));
		}

		return null;
	}


	public SubjectPublicKeyInfo( AlgorithmIdentifier algId, ASN1Encodable publicKey ) throws IOException {
		this.keyData = new DERBitString(publicKey);
		this.algId = algId;
	}


	public SubjectPublicKeyInfo( AlgorithmIdentifier algId, byte[] publicKey ) {
		this.keyData = new DERBitString(publicKey);
		this.algId = algId;
	}


	public SubjectPublicKeyInfo( ASN1Sequence seq ) {
		if ( seq.size() != 2 ) {
			throw new IllegalArgumentException("Bad sequence size: " + seq.size());
		}

		Enumeration e = seq.getObjects();

		this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
		this.keyData = DERBitString.getInstance(e.nextElement());
	}


	public AlgorithmIdentifier getAlgorithm() {
		return algId;
	}


	/**
	 * @deprecated use getAlgorithm()
	 * @return    alg ID.
	 */
	public AlgorithmIdentifier getAlgorithmId() {
		return algId;
	}


	/**
	 * for when the public key is an encoded object - if the bitstring
	 * can't be decoded this routine throws an IOException.
	 *
	 * @exception IOException - if the bit string doesn't represent a DER
	 * encoded object.
	 * @return the public key as an ASN.1 primitive.
	 */
	public ASN1Primitive parsePublicKey() throws IOException {
		ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes());

		return aIn.readObject();
	}


	/**
	 * for when the public key is an encoded object - if the bitstring
	 * can't be decoded this routine throws an IOException.
	 *
	 * @exception IOException - if the bit string doesn't represent a DER
	 * encoded object.
	 * @deprecated use parsePublicKey
	 * @return the public key as an ASN.1 primitive.
	 */
	public ASN1Primitive getPublicKey() throws IOException {
		ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes());

		return aIn.readObject();
	}


	/**
	 * for when the public key is raw bits.
	 *
	 * @return the public key as the raw bit string...
	 */
	public DERBitString getPublicKeyData() {
		return keyData;
	}


	/**
	 * Produce an object suitable for an ASN1OutputStream.
	 * <pre>
	 * SubjectPublicKeyInfo ::= SEQUENCE {
	 *                          algorithm AlgorithmIdentifier,
	 *                          publicKey BIT STRING }
	 * </pre>
	 */
	public ASN1Primitive toASN1Primitive() {
		ASN1EncodableVector v = new ASN1EncodableVector();

		v.add(algId);
		v.add(keyData);

		return new DERSequence(v);
	}
}

